/**
 * @file ringBuffer.c
 * @author xzq
 * @brief
 * @version 0.1
 * @date 2024-10-26
 *
 * @copyright Copyright (c) 2024
 *
 */
#include "stdio.h"
#include "string.h"
#include "stdlib.h"
#include "ringBuffer.h"

#define TAG "RINGBUFFER"
#define LOG_MESSAGE_DEBUG(TAG, ...)

/**
 * @brief xRingBuffer Lock
 *
 */
static void xRingBufferLock(void)
{
}

/**
 * @brief xRingBuffer Unlock
 *
 */
static void xRingBufferUnlock(void)
{
}

/**
 * @brief xRingBuffer Malloc Memery
 *
 * @param size
 * @return void*
 */
static void *xRingBufferMalloc(size_t size)
{
	return malloc(size);
}

/**
 * @brief xRingBuffer Free Memery
 *
 * @param memery
 */
static void xRingBufferFree(void *memery)
{
	free(memery);
}

/**
 * @brief xRingBuffer Create
 *
 * @param rb xRingBuffer_t *handle
 * @param size xRingBuffer Size
 * @return rbStatus_t
 */
rbStatus_t xRingBufferCreate(xRingBuffer_t *rb, uint32_t size)
{
	if (NULL == rb)
	{
		LOG_MESSAGE_DEBUG(TAG, "rbBuffer Create Fail,Malloc Memery Fail");
		return rbFail;
	}
	rb->rbBuffer = (int8_t *)xRingBufferMalloc(size);
	memset(rb->rbBuffer, 0, size);
	if (NULL == rb->rbBuffer)
	{
		return rbFail;
	}
	rb->rbSize = size;
	rb->rbHead = rb->rbBuffer;
	rb->rbTail = rb->rbBuffer;
	LOG_MESSAGE_DEBUG(TAG, "rbBuffer Create Success");
	return rbSuccess;
}

/**
 * @brief xRingBuffer Flush Buffer
 *
 * @param rb xRingBuffer_t *handle
 */
void xRingBufferFlush(xRingBuffer_t *rb)
{
	xRingBufferLock();
	rb->rbHead = rb->rbBuffer;
	rb->rbTail = rb->rbBuffer;
	memset(rb->rbBuffer, 0, rb->rbSize);
	xRingBufferUnlock();
	LOG_MESSAGE_DEBUG(TAG, "rbBuffer Flush Success");
}

/**
 * @brief xRingBuffer Destory
 *
 * @param rb xRingBuffer_t *handle
 * @return rbStatus_t
 */
rbStatus_t xRingBufferDestory(xRingBuffer_t *rb)
{
	if (NULL == rb)
	{
		LOG_MESSAGE_DEBUG(TAG, "rbBuffer Destory Fail,Has Not Handle");
		return rbFail;
	}
	xRingBufferFree(rb->rbBuffer);
	rb->rbHead = NULL;
	rb->rbTail = NULL;
	rb->rbSize = 0;
	rb->rbBuffer = NULL;
	LOG_MESSAGE_DEBUG(TAG, "rbBuffer Destory Success");
	return rbSuccess;
}

/**
 * @brief Get xRingBuffer Capacity
 *
 * @param rb RingBuffer_t *handle
 * @param capacity capacity
 * @return rbStatus_t
 */
rbStatus_t xRingBufferCapacity(xRingBuffer_t *rb, uint32_t *capacity)
{
	if (NULL == rb)
	{
		LOG_MESSAGE_DEBUG(TAG, "rbBuffer Get Capacity Fail");
		return rbFail;
	}
	if (NULL != capacity)
	{
		*capacity = rb->rbSize;
	}
	return rbSuccess;
}

/**
 * @brief Get xRingBuffer Can Read Size
 *
 * @param rb xRingBuffer_t *handle
 * @param can_read_size can Read Size Addr
 * @return rbStatus_t
 */
static rbStatus_t xRingBufferCanRead(xRingBuffer_t *rb, uint32_t *can_read_size)
{
	if ((NULL == rb) || (NULL == can_read_size))
	{
		LOG_MESSAGE_DEBUG(TAG, "rbBuffer Get Can Read Size Fail");
		return rbFail;
	}

	rbStatus_t rbReturn = rbFail;
	if (rb->rbHead == rb->rbTail)
	{
		*can_read_size = 0;
		rbReturn = rbSuccess;
		goto xReturn;
	}
	if (rb->rbTail > rb->rbHead)
	{
		*can_read_size = rb->rbTail - rb->rbHead;
		rbReturn = rbSuccess;
		goto xReturn;
	}
	*can_read_size = rb->rbSize - (rb->rbHead - rb->rbTail);
	rbReturn = rbSuccess;
xReturn:
	return rbReturn;
}

/**
 * @brief Get xRingBuffer Can Write Size
 *
 * @param rb xRingBuffer_t *handle
 * @param can_write_size  can Write Size Addr
 * @return rbStatus_t
 */
static rbStatus_t xRingBufferCanWrite(xRingBuffer_t *rb, uint32_t *can_write_size)
{
	if ((NULL == rb) || (NULL == can_write_size))
	{
		LOG_MESSAGE_DEBUG(TAG, "rbBuffer Get Can Write Fail");
		return rbFail;
	}
	uint32_t can_read_size = 0, capacity = 0;
	rbStatus_t rbReturn = rbFail;
	if (xRingBufferCanRead(rb, &can_read_size) != rbSuccess)
	{
		*can_write_size = 0;
		goto xReturn;
	}
	if (xRingBufferCapacity(rb, &capacity) != rbSuccess)
	{
		*can_write_size = 0;
		goto xReturn;
	}
	*can_write_size = capacity - can_read_size;
	rbReturn = rbSuccess;
xReturn:
	return rbReturn;
}

/**
 * @brief Get Number Min value
 *
 * @param a
 * @param b
 * @return uint32_t
 */
static uint32_t xRingBufferGetMin(uint32_t a, uint32_t b)
{
	if (a > b)
	{
		return b;
	}
	return a;
}

/**
 * @brief xRingBuffer Generic Read
 *
 * @param rb xRingBuffer_t *handle
 * @param date read Date
 * @param size read Size
 * @param read read Success Date Size
 * @return rbStatus_t
 */
rbStatus_t xRingBufferGenericRead(xRingBuffer_t *rb, void *date, uint32_t size, uint32_t *read)
{
	if (NULL == rb)
	{
		return rbFail;
	}
	if ((NULL == date) || (size <= 0))
	{
		return rbFail;
	}
	if (NULL != read)
	{
		*read = 0;
	}
	uint32_t copy_size = 0, can_read = 0, capacity = 0;
	rbStatus_t rbReturn = rbFail;

	xRingBufferLock();
	/*rbTail > rbHead*/
	if (rb->rbTail > rb->rbHead)
	{
		if (xRingBufferCanRead(rb, &can_read) == rbSuccess)
		{
			copy_size = xRingBufferGetMin(size, can_read);
			memcpy(date, rb->rbHead, copy_size);
			rb->rbHead += copy_size;
			if (NULL != read)
			{
				*read = copy_size;
			}
			rbReturn = rbSuccess;
			LOG_MESSAGE_DEBUG(TAG, "rbBuffer Read Success,Read Size %d Byte", copy_size);
		}
		goto xReturn;
	}
	else
	{ /* rbHead > rbTail*/
		/*show can read size*/
		if (xRingBufferCanRead(rb, &can_read) != rbSuccess)
		{
			goto xReturn;
		}
		if (can_read < size)
		{
			size = can_read;
		}
		if (xRingBufferCapacity(rb, &capacity) != rbSuccess)
		{
			goto xReturn;
		}
		if (size < (capacity - (rb->rbHead - rb->rbBuffer)))
		{
			copy_size = size;
			memcpy(date, rb->rbHead, copy_size);
			rb->rbHead += copy_size;
			if (NULL != read)
			{
				*read = copy_size;
			}
			rbReturn = rbSuccess;
			LOG_MESSAGE_DEBUG(TAG, "rbBuffer Read Success,Read Size %d Byte", copy_size);
			goto xReturn;
		}
		else
		{
			copy_size = capacity - (rb->rbHead - rb->rbBuffer);
			memcpy(date, rb->rbHead, copy_size);
			rb->rbHead = rb->rbBuffer;
			if (NULL != read)
			{
				*read = copy_size;
			}
			LOG_MESSAGE_DEBUG(TAG, "rbBuffer Read Success,Read Size %d Byte", copy_size);
			uint32_t temp_size = 0;
			if (size - copy_size <= 0)
			{
				rbReturn = rbSuccess;
				goto xReturn;
			}
			if (xRingBufferGenericRead(rb, (int8_t *)date + copy_size, size - copy_size, &temp_size) == rbSuccess)
			{
				if (NULL != read)
				{
					*read += temp_size;
				}
				rbReturn = rbSuccess;
			}
			goto xReturn;
		}
	}
xReturn:
	xRingBufferUnlock();
	return rbReturn;
}

/**
 * @brief xRingBuffer Generic Write
 *
 * @param rb xRingBuffer_t *handle
 * @param date write Date
 * @param size write size
 * @param write write Success Date Size
 * @return rbStatus_t
 */
rbStatus_t xRingBufferGenericWrite(xRingBuffer_t *rb, void *date, uint32_t size, uint32_t *write)
{
	if (NULL == rb)
	{
		return rbFail;
	}
	if ((NULL == date) || (size <= 0))
	{
		return rbFail;
	}
	if (NULL != write)
	{
		*write = 0;
	}
	uint32_t can_write = 0, write_size = 0, capacity = 0;
	rbStatus_t rbReturn = rbFail;

	if (xRingBufferCanWrite(rb, &can_write) != rbSuccess)
	{
		goto xReturn;
	}
	if (size >= can_write)
	{
		LOG_MESSAGE_DEBUG(TAG, "rbBuffer Write Space Not Enough,Write Fail");
		goto xReturn;
	}
	xRingBufferLock();
	if (rb->rbTail >= rb->rbHead)
	{
		if (xRingBufferCapacity(rb, &capacity) != rbSuccess)
		{
			goto xReturn;
		}
		write_size = capacity - (rb->rbTail - rb->rbBuffer);
		if (write_size >= size)
		{
			memcpy(rb->rbTail, date, size);
			rb->rbTail += size;
			if (NULL != write)
			{
				*write = size;
			}
			/*check current rbTail is not buffer End*/
			if (rb->rbTail >= rb->rbBuffer + capacity)
			{
				rb->rbTail = rb->rbBuffer;
			}
			rbReturn = rbSuccess;
			LOG_MESSAGE_DEBUG(TAG, "rbBuffer Write Success,Write %d Bytes", size);
			goto xReturn;
		}
		else
		{
			memcpy(rb->rbTail, date, write_size);
			rb->rbTail = rb->rbBuffer;
			if (NULL != write)
			{
				*write = write_size;
			}
			LOG_MESSAGE_DEBUG(TAG, "rbBuffer Write Success,Write %d Bytes", write_size);
			uint32_t temp_size = 0;
			if (xRingBufferGenericWrite(rb, (int8_t *)date + write_size, (size - write_size), &temp_size) == rbSuccess)
			{
				if (NULL != write)
				{
					*write += temp_size;
				}
				rbReturn = rbSuccess;
				goto xReturn;
			}
		}
	}
	else
	{
		memcpy(rb->rbTail, date, size);
		rb->rbTail += size;
		if (NULL != write)
		{
			*write = size;
		}
		LOG_MESSAGE_DEBUG(TAG, "rbBuffer Write Success,Write %d Bytes", size);
		rbReturn = rbSuccess;
	}
xReturn:
	xRingBufferUnlock();
	return rbReturn;
}

/**
 * @brief xRingBuffer Read
 *
 * @param rb xRingBuffer_t *handle
 * @param date read date
 * @param size read Size
 * @return rbStatus_t
 */
rbStatus_t xRingBufferRead(xRingBuffer_t *rb, void *date, uint32_t size)
{
	return xRingBufferGenericRead(rb, date, size, NULL);
}
/**
 * @brief xRingBuffer Write
 *
 * @param rb xRingBuffer_t * handle
 * @param date write Date
 * @param size write Size
 * @return rbStatus_t
 */
rbStatus_t xRingBufferWrite(xRingBuffer_t *rb, void *date, uint32_t size)
{
	return xRingBufferGenericWrite(rb, date, size, NULL);
}

/**
 * @brief xRingBuffer Can Read
 *
 * @param rb xRingBuffer_t *handle
 * @return rbStatus_t
 */
rbStatus_t xRingBufferIsRead(xRingBuffer_t *rb)
{
	uint32_t can_read = 0;
	if (xRingBufferCanRead(rb, &can_read) != rbSuccess)
	{
		return rbFail;
	}
	if (can_read > 0)
	{
		return rbSuccess;
	}
	return rbFail;
}